#include "Manager.h"
extern bool Collision(const core::Rectangle& A, const core::Rectangle& B);
namespace PickinOpenSticks {
    namespace Ui {
        /**
         * AddWidget: Adds a main widget to the manager
         * @param const string& name - The name of the widget(in case you want to modify it)
         * @param Widget* widget- the widget you want added
         * @author Adrian Tut
         * @date 21/10/2010
         */
        void Manager::AddWidget(const std::string &name, Widget *widget) {
            if (this->FindWidgetByName(name)) return;
            widget->SetName(name);
            widgets.insert(make_pair<int, Widget*>(++index, widget));

        }

        /**
         * Initialize: Starts the manager
         * @param RenderWindow renderTarget - a pointer to the window on which it will draw
         * @author Adrian Tut
         * @date 21/10/2010
         */
        void Manager::Initialize(sf::RenderWindow *renderTarget) {
            window = renderTarget;
            size.Setup(0, 0, window->GetWidth(), window->GetHeight());
            index = 0;
            focus = 0;
            hotSpotX = 0;
            hotSpotY = 0;
            drag = true;
        }

        /**
         * RegisterEvent: Registers a sf::Event
         * Manually registering events makes sure that they won't be lost
         * @param Event event- The event that occured
         * @author Adrian Tut
         * @date 21/10/2010
         */
        void Manager::RegisterEvent(sf::Event *event) {
            events.push_back(event);
        }

        /**
         * Update: Main update function
         * @param int diff- Time passed since last update
         * @author Adrian Tut
         * @date 21/10/2010
         */

        void Manager::Update(int diff) {
            //if there's no new events... just redraw and update
            if (!events.size()) {
                for (WidgetList::iterator i = widgets.begin(); i != widgets.end(); i++) {
                    i->second->Update(diff);
                    i->second->Draw(window);
                }
            } else {
                for (int i = 0; i < (int) events.size(); i++) {
                    sf::Event* curEvent = events[i];
                    WidgetList::reverse_iterator itr;
                    switch (curEvent->Type) {
                        case sf::Event::MouseButtonPressed:
                            for (itr = widgets.rbegin(); itr != widgets.rend(); itr++) {
                                int x = curEvent->MouseButton.X;
                                int y = curEvent->MouseButton.Y;
                                sf::Vector2f c = window->ConvertCoords(x, y);
                                x = (int) c.x;
                                y = (int) c.y;
                                if (Collision(core::Rectangle(x, y, 2, 2), itr->second->GetPos()) && itr->second->visible) {
                                    itr->second->RegisterEvent(curEvent);
                                    SetHasFocus(itr);
                                    //sf::Vector2f C = window->ConvertCoords(itr->second->GetPos().x,itr->second->GetPos().y);
                                    int X = itr->second->GetPos().x;
                                    int Y = itr->second->GetPos().y;
                                    StartDrag(x - X, y - Y);
                                    break;
                                }
                            }
                            //if a click happened a no widgets were clicked... there's no focus
                            if (itr == widgets.rend()) {
                                focus = 0;
                            }
                            break;
                        case sf::Event::MouseButtonReleased:
                        {
                            sf::Vector2f a = window->ConvertCoords(curEvent->MouseButton.X, curEvent->MouseButton.Y);
                            StopDrag((int) a.x, (int) a.y);
                            if (focus) focus->RegisterEvent(curEvent);
                            break;
                        }
                        case sf::Event::MouseMoved:
                            if (drag && focus) {
                                sf::Vector2f a = window->ConvertCoords(curEvent->MouseMove.X, curEvent->MouseMove.Y);

                                focus->Move((int) a.x - hotSpotX, (int) a.y - hotSpotY);
                            }
                            if (focus) focus->RegisterEvent(curEvent);
                            break;
                        case sf::Event::KeyPressed:
                        case sf::Event::KeyReleased:
                            if (focus) focus->RegisterEvent(curEvent);
                            break;
                        default: if (focus) focus->RegisterEvent(curEvent);
                    }
                    //we solved the events
                    events.clear();

                    for (WidgetList::iterator i = widgets.begin(); i != widgets.end(); i++) {
                        i->second->Update(diff);
                        i->second->Draw(window);
                    }

                }
            }
        }

        void Manager::SetHasFocus(Manager::WidgetList::reverse_iterator &i) {
            Widget* widget = i->second;
            i++;
            WidgetList::iterator itr = i.base();
            widgets.erase(itr);
            widgets.insert(make_pair<int, Widget*>(++index, widget));
            i = widgets.rbegin();
            focus = widget;

        }

        Widget* Manager::FindWidgetByName(const std::string& name) {
            for (WidgetList::iterator itr = widgets.begin(); itr != widgets.end(); itr++) {
                if (itr->second->GetName() == name) {
                    return itr->second;
                }
            }


            return 0;
        }

        void Manager::StartDrag(int hotSpotx, int hotSpoty) {
            hotSpotX = hotSpotx;
            hotSpotY = hotSpoty;
            drag = true;
        }

        void Manager::StopDrag(int x, int y) {
            //if(focus) focus->SetPos(x-hotSpotX, y-hotSpotY);
            drag = false;
        }

        vector<Widget*> Manager::GetWidgetsByType(WidgetType type) {
            vector<Widget*> chosen;
            for (WidgetList::iterator i = widgets.begin(); i != widgets.end(); i++) {
                if (i->second->GetType() == type)
                    chosen.push_back(i->second);
            }
            return chosen;
        }
    }
} //namespace Gui
